package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.api.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.file.FileStorageService;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.common.dto.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojo.WmChannel;
import com.heima.model.wemedia.pojo.WmNews;
import com.heima.model.wemedia.pojo.WmSensitive;
import com.heima.model.wemedia.pojo.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private IArticleClient articleClient;
    @Autowired
    private WmUserMapper userMapper;
    @Autowired
    private WmChannelMapper channelMapper;
    @Autowired
    private WmSensitiveMapper sensitiveMapper;

    @Override
    public void autoScanWmNews(Integer id) throws Exception {
        // 根据id查询文章对象
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (wmNews.getStatus() != WmNews.Status.SUBMIT.getCode()) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(wmNews.getTitle());
        // 提取content中所有文本
        stringBuilder.append(JSON.parseArray(wmNews.getContent(), HashMap.class).stream().filter(m -> "text".equals(m.get("type"))).map(m -> {
            // 获取所有文本字符串
            return (String) m.get("value");
        }).collect(Collectors.joining()));
        List<WmSensitive> wmSensitives = null;
        if (stringBuilder.length() != 0) {
            // 本地敏感词审核
            // 查询数据库中所有敏感词
            wmSensitives = sensitiveMapper.selectList(null);
            if (!CollectionUtils.isEmpty(wmSensitives)) {
                // 把敏感词字符提取
                List<String> sensitives = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
                // 初始化DFA词库
                SensitiveWordUtil.initMap(sensitives);
                Map<String, Integer> scanResult = SensitiveWordUtil.matchWords(stringBuilder.toString());
                if (scanResult.size() > 0) {
                    // 有敏感词，审核失败
                    // 审核失败
                    wmNews.setStatus(WmNews.Status.FAIL.getCode());
                    wmNews.setReason("文章中包含非法文本，审核失败：" + scanResult);
                    wmNewsMapper.updateById(wmNews);
                    return;
                }
            }

            // 文章文本审核  文本提取
            // Map中的suggestion有三种情况：pass  block  review
            Map textScanResult = greenTextScan.greeTextScan(stringBuilder.toString());
            if (textScanResult != null && "block".equals(textScanResult.get("suggestion"))) {
                // 审核失败
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("文章中包含非法文本，审核失败");
                wmNewsMapper.updateById(wmNews);
                return;
            } else if (textScanResult != null && "review".equals(textScanResult.get("suggestion"))) {
                // 需要人工审核
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                wmNews.setReason("审核结果不确定，需要人工审核");
                wmNewsMapper.updateById(wmNews);
                return;
            }
        }
        // 图片审核
        // 从minio下载图片
        List<String> imageUrlList = new ArrayList<>();
        // 封面图url获取
        if (StringUtils.hasLength(wmNews.getImages())) {
            imageUrlList.addAll(Arrays.asList(wmNews.getImages().split(",")));
        }
        // 提取内容中的所有图片的url
        List<String> contentImageUrlList = JSON.parseArray(wmNews.getContent(), HashMap.class).stream().filter(m -> "image".equals(m.get("type"))).map(m -> {
            // 获取所有文本字符串
            return (String) m.get("value");
        }).collect(Collectors.toList());
        imageUrlList.addAll(contentImageUrlList);

        if (imageUrlList.size() != 0) {
            List<byte[]> images = imageUrlList
                    .stream()
                    .distinct()// 去重，减少不必要的图片审核
                    .map(url -> fileStorageService.downLoadFile(url))
                    .collect(Collectors.toList());
            //创建Tesseract对象
            ITesseract tesseract = new Tesseract();
            //设置字体库路径
            tesseract.setDatapath(ClassLoader.getSystemClassLoader()
                    .getResource("ocr/tessdata").getPath().substring(1));
            //中文识别
            tesseract.setLanguage("chi_sim");

            // 本地图片审核  OCR提取文字审核  粗筛
            try {
                // 本地敏感词审核
                // 查询数据库中所有敏感词
                if(CollectionUtils.isEmpty(wmSensitives)){
                    wmSensitives = sensitiveMapper.selectList(null);
                }
                if (!CollectionUtils.isEmpty(wmSensitives)) {
                    // 把敏感词字符提取
                    List<String> sensitives = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
                    // 初始化DFA词库
                    SensitiveWordUtil.initMap(sensitives);
                    for (byte[] bytes : images) {
                        // 把字节数组转为内存中的图片对象
                        BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(bytes));
                        //执行ocr识别
                        String result = tesseract.doOCR(bufferedImage);
                        //替换回车和tal键  使结果为一行
                        result = result.replaceAll("\\r|\\n","-").replaceAll(" ","");
                        // 调用文字敏感词识别
                        Map<String, Integer> scanResult = SensitiveWordUtil.matchWords(result);
                        if (scanResult.size() > 0) {
                            // 有敏感词，审核失败
                            // 审核失败
                            wmNews.setStatus(WmNews.Status.FAIL.getCode());
                            wmNews.setReason("文章中包含非法文本，审核失败：" + scanResult);
                            wmNewsMapper.updateById(wmNews);
                            return;
                        }
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }



            Map imageScanResult = greenImageScan.imageScan(images);
            if (imageScanResult != null && "block".equals(imageScanResult.get("suggestion"))) {
                // 审核失败
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("文章中包含非法图片，审核失败");
                wmNewsMapper.updateById(wmNews);
                return;
            } else if (imageScanResult != null && "review".equals(imageScanResult.get("suggestion"))) {
                // 需要人工审核
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                wmNews.setReason("审核结果不确定，需要人工审核");
                wmNewsMapper.updateById(wmNews);
                return;
            }
        }
        // 说明审核成功，可以把状态修改为 8
        wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
        wmNews.setReason("审核成功");
        wmNewsMapper.updateById(wmNews);
        // 调用feign接口，保存文章到app端
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, articleDto);
        // 作者就是当前文章发布的user
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        WmUser user = userMapper.selectById(wmNews.getUserId());
        // 查询用户名称
        if (user != null && StringUtils.hasLength(user.getName())) {
            articleDto.setAuthorName(user.getName());
        }
        WmChannel wmChannel = channelMapper.selectById(wmNews.getChannelId());
        if (wmChannel != null && StringUtils.hasLength(wmChannel.getName())) {
            articleDto.setChannelName(wmChannel.getName());
        }
        articleDto.setPublishTime(new Date());
        articleDto.setLayout(CollectionUtils.isEmpty(contentImageUrlList) ?
                (short) 0 : contentImageUrlList.size() == 1 ? (short) 1 : (short) 2);

        // 远程调用微服务保存
        ResponseResult response = articleClient.save(articleDto);
        Long articleId = (Long) response.getData();
        // 修改当前表中的文章状态
        wmNews.setArticleId(articleId);
        wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
        wmNews.setPublishTime(articleDto.getPublishTime());
        wmNewsMapper.updateById(wmNews);
    }
}
